﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Threading;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

using CPXMenu;

using CPXMenuEditor.Forms;

namespace CPXMenuEditor.Controls
{
    public partial class ContentBrowser : UserControl
    {
        private MenuProject menuProject;
        private ImportedContentItem selectedContentItem = null;
        private Type contentType;
        private bool initialized = false;
        private bool initializing = false;
        private ImportedContentNode selectedNode = null;

        /// <summary>
        /// Gets the currently selected content file
        /// </summary>
        [Browsable(false)]
        public ImportedContentItem SelectedContentItem
        {
            get { return selectedContentItem; }
            set
            {
                ImportedContentItem prevFile = selectedContentItem;
                selectedContentItem = value;

                if (!initialized)
                    return;

                if (object.ReferenceEquals(prevFile, selectedContentItem))
                    return;

                SelectedNode = value;

                OnSelectedContentChanged();
            }
        }

        [Browsable(false)]
        public ImportedContentNode SelectedNode
        {
            get { return selectedNode; }
            set
            {
                ImportedContentNode prevNode = selectedNode;
                selectedNode = value;

                if (!initialized)
                    return;

                if (object.ReferenceEquals(prevNode, selectedNode))
                    return;

                if (value == null)
                    treeView.SelectedNode = null;
                else
                    treeView.SelectedNode = FindTreeNode(treeView.Nodes, value);

                SelectedContentItem = value as ImportedContentItem;

                OnSelectedNodeChanged();
            }
        }

        [Browsable(false)]
        public bool Initialized
        {
            get { return initialized; }
        }

        [Browsable(false)]
        public bool Initializing
        {
            get { return initializing; }
        }

        public ContentBrowser()
        {
            InitializeComponent();

            CenterProgressBar();
        }

        public void Initialize(string selectedContentFile, Type contentType, MenuProject menuProject)
        {
            if (initializing)
                return;

            initialized = false;
            initializing = true;

            treeView.Enabled = false;
            treeView.Nodes.Clear();

            this.contentType = contentType;
            this.menuProject = menuProject;                       

            BuildTree(treeView.Nodes, menuProject.ImportedContentRoot);

            treeView.Enabled = true;
            this.Cursor = Cursors.Default;

            initialized = true;
            initializing = false;

            if (LoadingComplete != null)
                LoadingComplete(this, EventArgs.Empty);

            SelectedContentItem = FindImportedContentItem(selectedContentFile);
        }

        protected virtual void OnSelectedContentChanged()
        {
            if (SelectedContentChanged != null)
                SelectedContentChanged(this, EventArgs.Empty);
        }

        protected virtual void OnSelectedNodeChanged()
        {
            if (SelectedNodeChanged != null)
                SelectedNodeChanged(this, EventArgs.Empty);
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);

            CenterProgressBar();
        }

        private ImportedContentItem FindImportedContentItem(string contentFile)
        {
            TreeNode treeNode = FindTreeNodeWithContent(treeView.Nodes, contentFile);
            if (treeNode == null)
                return null;
            else
                return treeNode.Tag as ImportedContentItem;
        }

        private TreeNode FindTreeNodeWithContent(TreeNodeCollection nodes, string contentFile)
        {
            foreach (TreeNode childNode in nodes)
            {
                if (childNode.Tag is ImportedContentItem && ((ImportedContentItem)childNode.Tag).Path == contentFile)
                    return childNode;
                else
                {
                    TreeNode result = FindTreeNodeWithContent(childNode.Nodes, contentFile);
                    if (result != null)
                        return result;
                }
            }

            return null;
        }

        private TreeNode FindTreeNode(TreeNodeCollection nodes, ImportedContentNode node)
        {
            foreach (TreeNode childNode in nodes)
            {
                if (object.ReferenceEquals(childNode.Tag, node))
                    return childNode;
                else
                {
                    TreeNode result = FindTreeNode(childNode.Nodes, node);
                    if (result != null)
                        return result;
                }
            }

            return null;
        }

        private void CenterProgressBar()
        {
            progressBar.Left = 50;
            progressBar.Width = this.Width - 100;
            progressBar.Top = (this.Height / 2) - (progressBar.Height / 2);
            loadingLabel.Top = progressBar.Top - 20;
            loadingLabel.Left = (this.Width / 2) - (loadingLabel.Width / 2);
        }            

        private string GetImageKey(Type contentType)
        {
            string imageKey = "Default";

            if (contentType == typeof(Model))
                imageKey = "Model";
            else if (contentType == typeof(Effect))
                imageKey = "Effect";
            else if (contentType == typeof(Model))
                imageKey = "Model";
            else if (contentType == typeof(SpriteFont))
                imageKey = "SpriteFont";
            else if (contentType == typeof(Texture)
                    || contentType == typeof(Texture2D)
                    || contentType == typeof(Texture3D)
                    || contentType == typeof(TextureCube))
                imageKey = "Texture";

            return imageKey;
        }

        private TreeNode MakeTreeNode(ImportedContentDirectory ImportedContentDirectory)
        {
            TreeNode treeNode = new TreeNode(ImportedContentDirectory.Name);
            treeNode.Tag = ImportedContentDirectory;
            treeNode.ImageKey = "FolderClosed";
            treeNode.SelectedImageKey = "FolderClosed";
            treeNode.Tag = ImportedContentDirectory;

            return treeNode;
        }

        private TreeNode MakeTreeNode(ImportedContentItem item)
        {
            TreeNode treeNode = new TreeNode(item.Name);
            treeNode.Tag = item;
            treeNode.ImageKey = GetImageKey(item.Type);
            treeNode.SelectedImageKey = treeNode.ImageKey;

            return treeNode;
        }

        /// <summary>
        /// Builds the TreeView nodes from the tree of enumerated content and directories.
        /// </summary>
        /// <param name="nodeCollection">The TreeNodeCollection that new nodes should be added to</param>
        /// <param name="ImportedContentDirectory">The ImportedContentDirectory representing the directory being added to the tree</param>
        private void BuildTree(TreeNodeCollection nodeCollection, ImportedContentDirectory directory)
        {
            nodeCollection.Clear();

            TreeNode treeNode = MakeTreeNode(directory);
            nodeCollection.Add(treeNode);

            foreach (ImportedContentDirectory node in directory.Directories)
                BuildTree(treeNode.Nodes, node);

            foreach (ImportedContentItem contentItem in directory.Content)
            {
                if (contentItem.Type == contentType || contentItem.Type.IsSubclassOf(contentType))
                {
                    TreeNode contentTreeNode = MakeTreeNode(contentItem);
                    treeNode.Nodes.Add(contentTreeNode);
                }
            }
        }

        /// <summary>
        /// Called after a node is selected in the TreeView
        /// </summary>
        /// <param name="sender">The TreeView that raised the event</param>
        /// <param name="e">Event arguments</param>
        private void treeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            SelectedNode = e.Node.Tag as ImportedContentNode;
        }

        /// <summary>
        /// Called after a node is expanded in the TreeView
        /// </summary>
        /// <param name="sender">The TreeView that raised the event</param>
        /// <param name="e">Event arguments</param>
        private void treeView_AfterExpand(object sender, TreeViewEventArgs e)
        {
            if (e.Node.Tag is ImportedContentDirectory)
            {
                e.Node.ImageKey = "FolderOpen";
                e.Node.SelectedImageKey = e.Node.ImageKey;
            }
        }

        /// <summary>
        /// Called after a node is collapsed in the TreeView
        /// </summary>
        /// <param name="sender">The TreeView that raised the event</param>
        /// <param name="e">Event arguments</param>
        private void treeView_AfterCollapse(object sender, TreeViewEventArgs e)
        {
            if (e.Node.Tag is ImportedContentDirectory)
            {
                e.Node.ImageKey = "FolderClosed";
                e.Node.SelectedImageKey = e.Node.ImageKey;
            }
        }

        public event EventHandler LoadingComplete;
        public event EventHandler SelectedContentChanged;
        public event EventHandler SelectedNodeChanged;


    }
}
